/***************************************************************************
*   Copyright (C) 2005 by Alexandr Nemish   *
*   atlanter@gmail.com   *
*                                                                         *
*   This program is free software; you can redistribute it and/or modify  *
*   it under the terms of the GNU General Public License as published by  *
*   the Free Software Foundation; either version 2 of the License, or     *
*   (at your option) any later version.                                   *
*                                                                         *
*   This program is distributed in the hope that it will be useful,       *
*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
*   GNU General Public License for more details.                          *
*                                                                         *
*   You should have received a copy of the GNU General Public License     *
*   along with this program; if not, write to the                         *
*   Free Software Foundation, Inc.,                                       *
*   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
***************************************************************************/
#include <kaccel.h>
#include <kaction.h>
#include <kcharsets.h>
#include <kconfig.h>
#include <kconfigdialog.h>
#include <kdebug.h>
#include <kdeversion.h>
#include <kencodingfiledialog.h>
#include <kfiledialog.h>
#include <kglobal.h>
#include <kinputdialog.h>
#include <kiconloader.h>
#include <klocale.h>
#include <kmessagebox.h>
#include <kprinter.h>
#include <kstatusbar.h>
#include <ksplashscreen.h>
#include <kstandarddirs.h>
#include <kstdaccel.h>
#include <kstdaction.h>
#include <kurl.h>
#include <kurldrag.h>
#include <kurlrequesterdlg.h>
#include <kio/netaccess.h>
#include <qdragobject.h>
#include <qpainter.h>
#include <qpaintdevicemetrics.h>
#include <qpixmap.h>
#include <qtextcodec.h>
#include "bookreader.h"
#include "pref.h"
#include "settings.h"
#include "settingsdlg.h"
#include "bookmarksholder.h"

namespace {
QStringList listEncodings()
{
	const QStringList encodings(KGlobal::charsets()->availableEncodingNames());
	QStringList availEncodings;
	for (int i=0; i < encodings.count(); ++i)
	{
		bool found = false;
		QTextCodec *codecForEnc = KGlobal::charsets()->codecForName(encodings[i], found);
		if (found)
			availEncodings << encodings[i];
	}
	return availEncodings;
}
}


BookReader::BookReader()
		: KMainWindow(0, "BookReader"),
		m_view(new BookWidget(this)),
		m_bmHolder(new BookmarksHolder()),
		m_fullScreenAction(0),
		m_splash(0),
		m_printer(0)
{

	QPixmap splash(KGlobal::dirs()->findResource("appdata",
											"themes/default/splash.png"));
	m_splash = new KSplashScreen(splash);
	m_splash->show();
	// accept dnd
	setAcceptDrops(true);

	// tell the KMainWindow that this is indeed the main widget
	setCentralWidget(m_view);

	// then, setup our actions
	setupActions();

	// and a status bar
	statusBar()->show();

	// Apply the create the main window and ask the mainwindow to
	// automatically save settings if changed: window size, toolbar
	// position, icon size, etc.  Also to add actions for the statusbar
	// toolbar, and keybindings if necessary.
	setupGUI();

	// allow the view to change the statusbar and caption
	connect(m_view, SIGNAL(signalChangeStatusbar(const QString&)),
	         this, SLOT(changeStatusbar(const QString&)));
	connect(m_view, SIGNAL(signalChangeCaption(const QString&)),
	         this, SLOT(changeCaption(const QString&)));

	readSettings();
	m_splash->finish(m_view);
}

BookReader::~BookReader()
{
	writeSettings();
	delete m_bmHolder;
	delete m_splash;
}

void BookReader::load(const KURL& url)
{
	QString target;
	// download the contents
	if (!KIO::NetAccess::download(url, target))
		return;

	recentFilesAction->addURL(url);
	setCaption(url.fileName());
	m_view->openURL(url);
	KIO::NetAccess::removeTempFile( target );
}

void BookReader::setupActions()
{
	KStdAction::openNew(this, SLOT(fileNew()), actionCollection());
	KStdAction::open(this, SLOT(fileOpen()), actionCollection());
	recentFilesAction = KStdAction::openRecent(this, 
										SLOT(slotURLSelected(const KURL &)), 
										actionCollection());
	KStdAction::save(this, SLOT(fileSave()), actionCollection());
	KStdAction::saveAs(this, SLOT(fileSaveAs()), actionCollection());
	KStdAction::print(this, SLOT(filePrint()), actionCollection());
	KStdAction::quit(kapp, SLOT(quit()), actionCollection());
	
	KStdAction::firstPage(this, SLOT(gotoFirstPage()), actionCollection());
	KStdAction::prior(this, SLOT(prevPage()), actionCollection());
	KStdAction::next(this, SLOT(nextPage()), actionCollection());
	KStdAction::lastPage(this, SLOT(gotoLastPage()), actionCollection());

	KStdAction::gotoPage(this, SLOT(gotoPage()), actionCollection());
	
	m_fullScreenAction = KStdAction::fullScreen(this, SLOT(fullScreen()), 
												actionCollection(), this);

	KStdAction::preferences(this, SLOT(optionsPreferences()), actionCollection());

	KConfig *config = kapp->config();
	recentFilesAction->loadEntries(config);

	// this doesn't do anything useful.  it's just here to illustrate
	// how to insert a custom menu and menu item
	/*
	KAction *custom = new KAction( i18n( "Cus&tom Menuitem" ), 0,
	                               this, SLOT( optionsPreferences() ),
	                               actionCollection(), "custom_action" );*/
}

void BookReader::saveProperties(KConfig *config)
{
	// the 'config' object points to the session managed
	// config file.  anything you write here will be available
	// later when this app is restored
	if (!m_view->currentURL().isEmpty())
	{
		config->writeEntry("lastURL", m_view->currentURL());
		config->writeEntry("currentPage", m_view->currentPage());
	}
}

void BookReader::readProperties(KConfig *config)
{
	// the 'config' object points to the session managed
	// config file.  this function is automatically called whenever
	// the app is being restored.  read in here whatever you wrote
	// in 'saveProperties'

	QString url = config->readPathEntry("lastURL");
	int currentPage = config->readEntry("currentPage").toInt();
	/* Disable forawhile
	if (!url.isEmpty())
	{
		m_view->openURL(KURL(url));
		m_view->setCurrentPage(currentPage);
	}
	*/
}

void BookReader::dragEnterEvent(QDragEnterEvent *event)
{
	// accept uri drops only
	event->accept(KURLDrag::canDecode(event));
}

void BookReader::dropEvent(QDropEvent *event)
{
	// this is a very simplistic implementation of a drop event.  we
	// will only accept a dropped URL.  the Qt dnd code can do *much*
	// much more, so please read the docs there
	KURL::List urls;

	// see if we can decode a URI.. if not, just ignore it
	if (KURLDrag::decode(event, urls) && !urls.isEmpty())
	{
		// okay, we have a URI.. process it
		const KURL & url = urls.first();

		// load in the file
		load(url);
	}
}

void BookReader::fileNew()
{
	// this slot is called whenever the File->New menu is selected,
	// the New shortcut is pressed (usually CTRL+N) or the New toolbar
	// button is clicked

	// create a new window
	(new BookReader)->show();
}

void BookReader::fileOpen()
{
	// this slot is called whenever the File->Open menu is selected,
	// the Open shortcut is pressed (usually CTRL+O) or the Open toolbar
	// button is clicked
	/*
	    // this brings up the generic open dialog
	    KURL url = KURLRequesterDlg::getURL(QString::null, this, i18n("Open Location") );
	*/
	// standard filedialog
	KEncodingFileDialog::Result res = 
			KEncodingFileDialog::getOpenURLAndEncoding(
				listEncodings()[Settings::defaultEncoding()]);
	KURL url = res.URLs.front();
	m_view->setEncoding(res.encoding);
	if (!url.isEmpty())
		load(url);
}

void BookReader::fileSave()
{
	// this slot is called whenever the File->Save menu is selected,
	// the Save shortcut is pressed (usually CTRL+S) or the Save toolbar
	// button is clicked

	// save the current file
}

void BookReader::fileSaveAs()
{
	// this slot is called whenever the File->Save As menu is selected,
	KURL file_url = KFileDialog::getSaveURL();
	if (!file_url.isEmpty() && file_url.isValid())
	{
		// save your info, here
	}
}

void BookReader::filePrint()
{
	// this slot is called whenever the File->Print menu is selected,
	// the Print shortcut is pressed (usually CTRL+P) or the Print toolbar
	// button is clicked
	if (!m_printer) m_printer = new KPrinter;
	if (m_printer->setup(this))
	{
		// setup the printer.  with Qt, you always "print" to a
		// QPainter.. whether the output medium is a pixmap, a screen,
		// or paper
		QPainter p;
		p.begin(m_printer);

		// we let our view do the actual printing
		QPaintDeviceMetrics metrics(m_printer);
		//m_view->print( &p, metrics.height(), metrics.width() );

		// and send the result to the printer
		p.end();
	}
}

void BookReader::optionsPreferences()
{
	if (KConfigDialog::showDialog("settings"))
		return ;

	KConfigDialog *dialog = new KConfigDialog(this, "settings", Settings::self(),
	                        KDialogBase::IconList);
	SettingsWidget *general = new SettingsWidget(0, "General");
	
	const QStringList encodings(listEncodings());
	
	QString curEncoding(encodings[Settings::defaultEncoding()]);
	if (curEncoding.isEmpty())
		curEncoding = QString::fromLatin1(KGlobal::locale()->encoding());
	
	general->kcfg_DefaultEncoding->clear();
	general->kcfg_DefaultEncoding->insertStringList(encodings);
	for (int i=0; i < encodings.count(); ++i)
		if (encodings[i] == curEncoding)
			general->kcfg_DefaultEncoding->setCurrentItem(i);

	dialog->addPage(general, i18n("General"), "settings");
	connect(dialog, SIGNAL(settingsChanged()), this, SLOT(loadSettings()));
	dialog->show();
}

void BookReader::changeStatusbar(const QString& text)
{
	// display the text on the statusbar
	statusBar()->message(text);
}

void BookReader::changeCaption(const QString& text)
{
	// display the text on the caption
	setCaption(text);
}

void BookReader::loadSettings()
{
	m_view->setFont(Settings::font());
	m_view->setParaOffset(Settings::paraOffset());
	m_view->setEncoding(Settings::defaultEncoding());
}

void BookReader::slotURLSelected(const KURL & url)
{
	load(url);
}

bool BookReader::queryExit()
{
	recentFilesAction->saveEntries(KGlobal::config());
	return true;
}

void BookReader::writeSettings()
{
	KConfig * config = kapp->config();
	config->writeEntry("size", m_view->size());
	config->writeEntry("lastURL", m_view->currentURL());
	config->writeEntry("lastURLPage", m_view->currentPage());
	recentFilesAction->saveEntries(KGlobal::config());
}

void BookReader::readSettings()
{
	recentFilesAction->loadEntries(KGlobal::config());
	recentFilesAction->setEnabled(true); // force enabling
	
	m_view->setParaOffset(Settings::paraOffset());
	m_view->setEncodings(listEncodings());
	m_view->setEncoding(Settings::defaultEncoding());

	if (Settings::loadLastUrl())
 		loadLastUrl();
}

void BookReader::fullScreen()
{

	if (m_fullScreenAction->isChecked())
	{
		KMessageBox::information(this, "asdf", "asdf");
		//m_view->setWindowState( m_view->windowState() | WindowFullScreen );
		m_view->showFullScreen();
		//m_view->update();
	}
	else
	{
		m_view->setWindowState(m_view->windowState() & ~WindowFullScreen);
	}
}

void BookReader::loadLastUrl()
{
	KConfig * config = kapp->config();
	QSize size = config->readSizeEntry("size");
	lastURL = config->readEntry("lastURL");
	connect(m_view, SIGNAL(loadingFinished()), this, SLOT(loadLastURLSetPage()));
	if (!lastURL.isEmpty())
	{
		kdDebug() << "loadLastUrl: initial size = " << m_view->size() << endl;
		m_view->resize(size);
		kdDebug() << "loadLastUrl: resize = " << m_view->size() << endl;
		m_view->setupPageSize();
		kdDebug() << "render = 1" << endl;
		load(lastURL);
	}
}

void BookReader::loaded(int loaded)
{
	//m_loaded = loaded;
	m_splash->message(tr("Loading: %1 - %2%").arg(lastURL.fileName()).arg(loaded));
}

void BookReader::gotoFirstPage()
{
	m_view->firstPage();
}

void BookReader::nextPage()
{
	m_view->nextPage();
}

void BookReader::prevPage()
{
	m_view->prevPage();
}

void BookReader::gotoLastPage( )
{
	m_view->lastPage();
}

void BookReader::gotoPage()
{
	bool isOk;
	int page = KInputDialog::getInteger("Goto page", "Page number", 
										m_view->currentPage(), 1, 
										m_view->pageCount(), 1, &isOk);
	m_view->setCurrentPage(page - 1);
}

void BookReader::loadLastURLSetPage()
{
	int lastURLPage = kapp->config()->readNumEntry("lastURLPage");
	m_view->setCurrentPage(lastURLPage);
}
#include "bookreader.moc"
